home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / umich / network / ka9q / ka9q_src.arc / TCPIN.C < prev    next >
C/C++ Source or Header  |  1988-07-28  |  21KB  |  808 lines

  1. /* Process incoming TCP segments. Page number references are to ARPA RFC-793,
  2.  * the TCP specification.
  3.  */
  4.  
  5. #include "global.h"
  6. #include "timer.h"
  7. #include "mbuf.h"
  8. #include "netuser.h"
  9. #include "internet.h"
  10. #include "tcp.h"
  11. #include "icmp.h"
  12. #include "iface.h"
  13. #include "ip.h"
  14.  
  15. struct tcp_stat tcp_stat;
  16.  
  17. /* This function is called from IP with the IP header in machine byte order,
  18.  * along with a mbuf chain pointing to the TCP header.
  19.  */
  20. void
  21. tcp_input(bp,protocol,source,dest,tos,length,rxbroadcast)
  22. struct mbuf *bp;    /* Data field, if any */
  23. char protocol;        /* Should always be TCP_PTCL */
  24. int32 source;        /* Remote IP address */
  25. int32 dest;        /* Our IP address */
  26. char tos;        /* Type of Service */
  27. int16 length;        /* Length of data field */
  28. char rxbroadcast;    /* Incoming broadcast - discard if true */
  29. {
  30.     void reset(),update();
  31.     void proc_syn(),send_syn(),add_reseq(),get_reseq(),unlink_tcb();
  32.  
  33.     register struct tcb *tcb;    /* TCP Protocol control block */
  34.     struct tcp seg;            /* Local copy of segment header */
  35.     struct connection conn;        /* Local copy of addresses */
  36.     struct pseudo_header ph;    /* Pseudo-header for checksumming */
  37.     int hdrlen;            /* Length of TCP header */
  38.  
  39.     if(bp == NULLBUF)
  40.         return;
  41.  
  42.     if(rxbroadcast){
  43.         /* Any TCP packet arriving as a broadcast is
  44.          * to be completely IGNORED!!
  45.          */
  46.         tcp_stat.bdcsts++;
  47.         free_p(bp);
  48.         return;
  49.     }
  50.     ph.source = source;
  51.     ph.dest = dest;
  52.     ph.protocol = protocol;
  53.     ph.length = length;
  54.     if(cksum(&ph,bp,length) != 0){
  55.         /* Checksum failed, ignore segment completely */
  56.         tcp_stat.checksum++;
  57.         free_p(bp);
  58.         return;
  59.     }
  60.     /* Form local copy of TCP header in host byte order */
  61.     if((hdrlen = ntohtcp(&seg,&bp)) < 0){
  62.         /* TCP header is too small */
  63.         tcp_stat.runt++;
  64.         free_p(bp);
  65.         return;
  66.     }
  67.     length -= hdrlen;
  68.  
  69.     /* Fill in connection structure and find TCB */
  70.     conn.local.address = dest;
  71.     conn.local.port = seg.dest;
  72.     conn.remote.address = source;
  73.     conn.remote.port = seg.source;
  74.     
  75.     if((tcb = lookup_tcb(&conn)) == NULLTCB){
  76.         struct tcb *ntcb;
  77.         void link_tcb();
  78.  
  79.         /* Check that this segment carries a SYN, and that
  80.          * there's a LISTEN on this socket with
  81.          * unspecified source address and port
  82.          */
  83.         conn.remote.address = 0;
  84.         conn.remote.port = 0;
  85.         if(!(seg.flags & SYN) || (tcb = lookup_tcb(&conn)) == NULLTCB){
  86.             /* No unspecified LISTEN either, so reject */
  87.             free_p(bp);
  88.             reset(source,dest,tos,length,&seg);
  89.             return;
  90.         }
  91.         /* We've found an server listen socket, so clone the TCB */
  92.         if(tcb->flags & CLONE){
  93.             if((ntcb = (struct tcb *)malloc(sizeof (struct tcb))) == NULLTCB){
  94.                 free_p(bp);
  95.                 /* This may fail, but we should at least try */
  96.                 reset(source,dest,tos,length,&seg);
  97.                 return;
  98.             }
  99.             ASSIGN(*ntcb,*tcb);
  100.             tcb = ntcb;
  101.             tcb->timer.arg = (char *)tcb;
  102.         } else
  103.             unlink_tcb(tcb);    /* It'll be put back on later */
  104.  
  105.         /* Stuff the foreign socket into the TCB */
  106.         tcb->conn.remote.address = source;
  107.         tcb->conn.remote.port = seg.source;
  108.  
  109.         /* NOW put on right hash chain */
  110.         link_tcb(tcb);
  111.     }
  112.     /* Do unsynchronized-state processing (p. 65-68) */
  113.     switch(tcb->state){
  114.     case CLOSED:
  115.         free_p(bp);
  116.         reset(source,dest,tos,length,&seg);
  117.         return;
  118.     case LISTEN:
  119.         if(seg.flags & RST){
  120.             free_p(bp);
  121.             return;
  122.         }
  123.         if(seg.flags & ACK){
  124.             free_p(bp);
  125.             reset(source,dest,tos,length,&seg);
  126.             return;
  127.         }
  128.         if(seg.flags & SYN){
  129.  
  130.             /* (Security check is bypassed) */
  131.             /* page 66 */
  132.             tcp_stat.conin++;
  133.             proc_syn(tcb,tos,&seg);
  134.             send_syn(tcb);
  135.             setstate(tcb,SYN_RECEIVED);        
  136.             if(length != 0 || seg.flags & FIN) {
  137.                 break;        /* Continue processing if there's more */
  138.             }
  139.             tcp_output(tcb);
  140.         }
  141.         free_p(bp);    /* Unlikely to get here directly */
  142.         return;
  143.     case SYN_SENT:
  144.         if(seg.flags & ACK){
  145.             if(!seq_within(seg.ack,tcb->iss+1,tcb->snd.nxt)){
  146.                 free_p(bp);
  147.                 reset(source,dest,tos,length,&seg);
  148.                 return;
  149.             }
  150.         }
  151.         if(seg.flags & RST){    /* p 67 */
  152.             if(seg.flags & ACK){
  153.                 /* The ack must be acceptable since we just checked it.
  154.                  * This is how the remote side refuses connect requests.
  155.                  */
  156.                 close_self(tcb,RESET);
  157.             }
  158.             free_p(bp);
  159.             return;
  160.         }
  161.         /* (Security check skipped here) */
  162.         /* Check incoming precedence; it must match if there's an ACK */
  163.         if((seg.flags & ACK) && PREC(tos) != PREC(tcb->tos)){
  164.             free_p(bp);
  165.             reset(source,dest,tos,length,&seg);
  166.             return;
  167.         }
  168.         if(seg.flags & SYN){
  169.             proc_syn(tcb,tos,&seg);
  170.             if(seg.flags & ACK){
  171.                 /* Our SYN has been acked, otherwise the ACK
  172.                  * wouldn't have been valid.
  173.                  */
  174.                 update(tcb,&seg);
  175.                 setstate(tcb,ESTABLISHED);
  176.             } else {
  177.                 setstate(tcb,SYN_RECEIVED);
  178.             }
  179.             if(length != 0 || (seg.flags & FIN)) {
  180.                 break;        /* Continue processing if there's more */
  181.             }
  182.             tcp_output(tcb);
  183.         } else {
  184.             free_p(bp);    /* Ignore if neither SYN or RST is set */
  185.         }
  186.         return;
  187.     }
  188.     /* We reach this point directly in any synchronized state. Note that
  189.      * if we fell through from LISTEN or SYN_SENT processing because of a
  190.      * data-bearing SYN, window trimming and sequence testing "cannot fail".
  191.      */
  192.  
  193.     /* Trim segment to fit receive window. */
  194.     if(trim(tcb,&seg,&bp,&length) == -1){
  195.         /* Segment is unacceptable */
  196.         if(!(seg.flags & RST)){
  197.             tcb->flags |= FORCE;
  198.             tcp_output(tcb);
  199.         }
  200.         return;
  201.     }
  202.     /* If segment isn't the next one expected, and there's data
  203.      * or flags associated with it, put it on the resequencing
  204.      * queue and return. Don't send anything in reply.
  205.      *
  206.      * Processing the ACK in an out-of-sequence segment without
  207.      * flags or data should be safe, however.
  208.      */
  209.     if(seg.seq != tcb->rcv.nxt
  210.      && (length != 0 || (seg.flags & (SYN|FIN)) )){
  211.         add_reseq(tcb,tos,&seg,bp,length);
  212.         return;
  213.     }
  214.     /* This loop first processes the current segment, and then
  215.      * repeats if it can process the resequencing queue.
  216.      */
  217.     for(;;){
  218.         /* We reach this point with an acceptable segment; all data and flags
  219.          * are in the window, and the starting sequence number equals rcv.nxt
  220.          * (p. 70)
  221.          */    
  222.         if(seg.flags & RST){
  223.             if(tcb->state == SYN_RECEIVED && !(tcb->flags & CLONE)){
  224.                 /* Go back to listen state only if this was
  225.                  * not a cloned server TCB
  226.                  */
  227.                 setstate(tcb,LISTEN);
  228.             } else {
  229.                 close_self(tcb,RESET);
  230.             }
  231.             free_p(bp);
  232.             return;
  233.         }
  234.         /* (Security check skipped here) p. 71 */
  235.         /* Check for precedence mismatch or erroneous extra SYN */
  236.         if(PREC(tos) != PREC(tcb->tos) || (seg.flags & SYN)){
  237.             free_p(bp);
  238.             reset(source,dest,tos,length,&seg);
  239.             return;
  240.         }
  241.         /* Check ack field p. 72 */
  242.         if(!(seg.flags & ACK)){
  243.             free_p(bp);    /* All segments after synchronization must have ACK */
  244.             return;
  245.         }
  246.         /* Process ACK */
  247.         switch(tcb->state){
  248.         case SYN_RECEIVED:
  249.             if(seq_within(seg.ack,tcb->snd.una+1,tcb->snd.nxt)){
  250.                 update(tcb,&seg);
  251.                 setstate(tcb,ESTABLISHED);
  252.             } else {
  253.                 free_p(bp);
  254.                 reset(source,dest,tos,length,&seg);
  255.                 return;
  256.             }
  257.             break;
  258.         case ESTABLISHED:
  259.         case CLOSE_WAIT:
  260.             update(tcb,&seg);
  261.             break;
  262.         case FINWAIT1:    /* p. 73 */
  263.             update(tcb,&seg);
  264.             if(tcb->sndcnt == 0){
  265.                 /* Our FIN is acknowledged */
  266.                 setstate(tcb,FINWAIT2);
  267.             }
  268.             break;
  269.         case FINWAIT2:
  270.             update(tcb,&seg);
  271.             break;
  272.         case CLOSING:
  273.             update(tcb,&seg);
  274.             if(tcb->sndcnt == 0){
  275.                 /* Our FIN is acknowledged */
  276.                 setstate(tcb,TIME_WAIT);
  277.                 tcb->timer.start = MSL2;
  278.                 start_timer(&tcb->timer);
  279.             }
  280.             break;
  281.         case LAST_ACK:
  282.             update(tcb,&seg);
  283.             if(tcb->sndcnt == 0){
  284.                 /* Our FIN is acknowledged, close connection */
  285.                 close_self(tcb,NORMAL);
  286.                 return;
  287.             }            
  288.         case TIME_WAIT:
  289.             tcb->flags |= FORCE;
  290.             start_timer(&tcb->timer);
  291.         }
  292.  
  293.         /* (URGent bit processing skipped here) */
  294.  
  295.         /* Process the segment text, if any, beginning at rcv.nxt (p. 74) */
  296.         if(length != 0){
  297.             switch(tcb->state){
  298.             case SYN_RECEIVED:
  299.             case ESTABLISHED:
  300.             case FINWAIT1:
  301.             case FINWAIT2:
  302.                 /* Place on receive queue */
  303.                 append(&tcb->rcvq,bp);
  304.                 tcb->rcvcnt += length;
  305.                 tcb->rcv.nxt += length;
  306.                 tcb->rcv.wnd -= length;
  307.                 tcb->flags |= FORCE;
  308.                 break;
  309.             default:
  310.                 /* Ignore segment text */
  311.                 free_p(bp);
  312.                 break;
  313.             }
  314.         }
  315.         /* If the user has set up a r_upcall function and there's
  316.          * data to be read, notify him.
  317.          *
  318.          * This is done before sending an acknowledgement,
  319.          * to give the use